/**
 * // Copyright (c) 2023 KylinOS. All rights reserved.
 * //
 * // This program is free software; you can redistribute it
 * // and/or modify it under the terms of the GNU General Public
 * // License (version 2) as published by the FSF - Free Software
 * // Foundation*
 */

/**
 * // Copyright (C) 2023 ben LG <guoliben@kylinos.cn>
 */

package docextractor

import (
	"bytes"
	"os/exec"
	"strings"
	"time"

	//"github.com/xuri/excelize/v2"
	//"github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/thedatashed/xlsxreader"

	"gitee.com/guoliben/kydlp-doctotext/extractor_interface"
	"gitee.com/guoliben/kydlp-doctotext/utils/ctrlledprint"
)

type DocExcelX struct{}

func (extractor DocExcelX) GetTextFromFile(path string, size int64, filetype string, depth int) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(file)文档...")

	start := time.Now()

	var text []byte
	var b bytes.Buffer
	xl, err := xlsxreader.OpenFile(path)
	if err != nil || xl == nil {
		ctrlledprint.Println("Error opening xlsx file:", err)
		return nil, ""
	}
	for sheet := range xl.Sheets {
		for row := range xl.ReadRows(xl.Sheets[sheet]) {
			for r := range row.Cells {
				b.WriteString(row.Cells[r].Value)
			}
		}
	}
	text = b.Bytes()
	xl.Close()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocExcelX) GetTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(buffer)文档...")

	start := time.Now()

	var text []byte
	var b bytes.Buffer
	xl, err := xlsxreader.NewReader(data)
	if err != nil || xl == nil {
		ctrlledprint.Println("Error creating xlsx reader:", err)
		return nil, ""
	}
	for sheet := range xl.Sheets {
		for row := range xl.ReadRows(xl.Sheets[sheet]) {
			for r := range row.Cells {
				b.WriteString(row.Cells[r].Value)
			}
		}
	}
	text = b.Bytes()
	xl = nil

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocExcelX) GetStringTextFromFile(path string, size int64, filetype string, depth int) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(file)文档...")

	start := time.Now()

	var text string
	var b strings.Builder
	xl, err := xlsxreader.OpenFile(path)
	if err != nil || xl == nil {
		ctrlledprint.Println("Error opening xlsx file:", err)
		return "", ""
	}
	for sheet := range xl.Sheets {
		for row := range xl.ReadRows(xl.Sheets[sheet]) {
			for r := range row.Cells {
				b.WriteString(row.Cells[r].Value)
			}
		}
	}
	text = b.String()
	xl.Close()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocExcelX) GetStringTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(buffer)文档...")

	start := time.Now()

	var text string
	var b strings.Builder
	xl, err := xlsxreader.NewReader(data)
	if err != nil || xl == nil {
		ctrlledprint.Println("Error creating xlsx reader:", err)
		return "", ""
	}
	for sheet := range xl.Sheets {
		for row := range xl.ReadRows(xl.Sheets[sheet]) {
			for r := range row.Cells {
				b.WriteString(row.Cells[r].Value)
			}
		}
	}
	text = b.String()
	xl = nil

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func xlsxProcessFile(path string) ([]byte, error) {
	// 构建XLSX任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "xlsxtask", "--file", path)

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(file)任务出错:", errOut.String())
		return nil, err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(file)任务成功，输出:", out.String())
		return out.Bytes(), nil
	}
}

func xlsxProcessBuffer(path string) ([]byte, error) {
	// 构建XLSX任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "xlsxtask", "--buffer")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(buffer)任务出错:", errOut.String())
		return nil, err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(buffer)任务成功，输出:", out.String())
		return out.Bytes(), nil
	}
}

func xlsxProcessFileReturnString(path string) (string, error) {
	// 构建XLSX任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "xlsxtask", "--file", path)

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(file)任务出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(file)任务成功，输出:", out.String())
		return out.String(), nil
	}
}

func xlsxProcessBufferReturnString(path string) (string, error) {
	// 构建XLSX任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "xlsxtask", "--buffer")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(buffer)任务出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理XLSX(buffer)任务成功，输出:", out.String())
		return out.String(), nil
	}
}

func xlsxGetTextFromFile(path string, size int64, filetype string) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(file)文档...")

	start := time.Now()

	text, _ := xlsxProcessFile(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func xlsxGetTextFromBuffer(path string, data []byte, size int64, filetype string) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(buffer)文档...")

	xlsxtask := DocumentBufferTask{
		FileContent: data,
		FileSize: size,
		FileType: filetype,
	}
	err := XlsXBufferTaskQueue.Enqueue(xlsxtask)
	if err != nil {
		ctrlledprint.Println("XLSX(buffer)文档任务入队失败:", err)
		return nil, ""
	} else {
		ctrlledprint.Println("XLSX(buffer)文档任务入队成功!")
	}
	ctrlledprint.Println("---> XLSX(buffer)文档任务队列容量:", XlsXBufferTaskQueue.GetCap(), "已经入队的任务数:", XlsXBufferTaskQueue.GetLen())

	start := time.Now()

	text, _ := xlsxProcessBuffer(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func xlsxGetStringTextFromFile(path string, size int64, filetype string) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(file)文档...")

	start := time.Now()

	text, _ := xlsxProcessFileReturnString(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func xlsxGetStringTextFromBuffer(path string, data []byte, size int64, filetype string) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析xlsx(buffer)文档...")

	xlsxtask := DocumentBufferTask{
		FileContent: data,
		FileSize: size,
		FileType: filetype,
	}
	err := XlsXBufferTaskQueue.Enqueue(xlsxtask)
	if err != nil {
		ctrlledprint.Println("XLSX(buffer)文档任务入队失败:", err)
		return "", ""
	} else {
		ctrlledprint.Println("XLSX(buffer)文档任务入队成功!")
	}
	ctrlledprint.Println("---> XLSX(buffer)文档任务队列容量:", XlsXBufferTaskQueue.GetCap(), "已经入队的任务数:", XlsXBufferTaskQueue.GetLen())

	start := time.Now()

	text, _ := xlsxProcessBufferReturnString(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocExcelX) GetTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = xlsxGetTextFromFile(path, size, filetype)
	} else {
		text, elapsed = extractor.GetTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocExcelX) GetTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = xlsxGetTextFromBuffer(path, data, size, filetype)
	} else {
		text, elapsed = extractor.GetTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocExcelX) GetStringTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = xlsxGetStringTextFromFile(path, size, filetype)
	} else {
		text, elapsed = extractor.GetStringTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocExcelX) GetStringTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = xlsxGetStringTextFromBuffer(path, data, size, filetype)
	} else {
		text, elapsed = extractor.GetStringTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}
